package com.dreamchaser.familydevice.shiro.filter;


import com.alibaba.fastjson.JSON;
import com.dreamchaser.familydevice.constant.ResponseCode;
import com.dreamchaser.familydevice.domain.MessageVO;
import com.dreamchaser.familydevice.service.IAccountService;
import com.dreamchaser.familydevice.shiro.token.JwtToken;
import com.dreamchaser.familydevice.util.system.IpUtil;
import com.dreamchaser.familydevice.util.system.RequestResponseUtil;
import com.dreamchaser.familydevice.util.system.ResponseUtil;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.stream.Stream;


/**
 * 拦截器
 */
@Slf4j
public class RestJwtFilter extends RestPathMatchingFilter {

    private StringRedisTemplate redisTemplate;
    private com.dreamchaser.familydevice.service.IAccountService IAccountService;

    /**
     * 是否允许访问
     *
     * @param servletRequest
     * @param servletResponse
     * @param mappedValue     【】中的角色
     * @return
     * @throws Exception
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) throws Exception {

        Subject subject = getSubject(servletRequest, servletResponse);
        HttpServletRequest request = WebUtils.toHttp(servletRequest);
        HttpServletResponse response = WebUtils.toHttp(servletResponse);
        /**
         * 过滤
         */
        String path = request.getRequestURL().toString();
        String jwt = request.getHeader("Authorization");
        String uri = request.getRequestURI();
        String method = request.getMethod();
        log.debug("jwt:" + jwt);

        if (StringUtils.isEmpty(jwt)) {
            log.info("jwt:jwt is empty");
            response.setStatus(ResponseCode.NO_LOGIN);
            return false;
        }
//
        // 创建认证token
        AuthenticationToken token = createJwtToken(request, jwt);
        String msg;
        try {
            subject.login(token);
        } catch (UnknownAccountException e) {
            msg = "账号不存在！";
            MessageVO messageVo = new MessageVO().back(ResponseCode.RE_LOGIN, e.getMessage());
            ResponseUtil.responseWrite(JSON.toJSONString(messageVo), servletResponse);
            return false;
        } catch (LockedAccountException e) {
            e.printStackTrace();
            msg = "账号被锁定！";
        } catch (DisabledAccountException e) {
            e.printStackTrace();
            msg = "账号被禁用！";
        } catch (IncorrectCredentialsException e) {
            msg = "凭证/密码错误！";
            MessageVO messageVo = new MessageVO().back(ResponseCode.PASSWORD_MODIFY, e.getMessage());
            ResponseUtil.responseWrite(JSON.toJSONString(messageVo), servletResponse);
            return false;
        } catch (ExpiredJwtException e) { //jwt
            msg = "登陆超时";
            MessageVO messageVo = new MessageVO().back(ResponseCode.RE_LOGIN, e.getMessage());
            ResponseUtil.responseWrite(JSON.toJSONString(messageVo), servletResponse);
            return false;
        } catch (ExpiredCredentialsException e) {
            e.printStackTrace();
            msg = "凭证/密码过期！";
        } catch (ExcessiveAttemptsException e) {
            e.printStackTrace();
            msg = "登录失败次数过多！";
        } catch (AuthenticationException e) { // jwt错误
            MessageVO messageVo = new MessageVO().back(ResponseCode.ERROR_LOGIN, e.getMessage());
            ResponseUtil.responseWrite(JSON.toJSONString(messageVo), servletResponse);
            return false;
        } catch (Exception e) {
            MessageVO messageVo = new MessageVO().back(ResponseCode.ERROR_LOGIN, e.getMessage());
            ResponseUtil.responseWrite(JSON.toJSONString(messageVo), servletResponse);
            return false;
        }

        // 判断是否有对应的权限url
        //subject.checkPermission(WebUtils.getPathWithinApplication(request) + "==" + method);
//
//
//            // 刷新token
//            Account account = refreshToken(response, jwt);
//            request.setAttribute("currentUser", account);
//            return true;
//        } catch (Exception e) {
//            log.error("jwt解析错误", e);
//            response.setStatus(ResponseCode.NO_AUTH);
//            return false;
//        }
//        response.setStatus(ResponseCode.OK);
        request.setAttribute("currentUser", jwt);
        return true;
        //endregion
    }

    /**
     * 当isAccessAllowed返回false拒绝访问时处理
     *
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        Subject subject = getSubject(servletRequest, servletResponse);

        // 未认证的情况
//        if (null == subject || !subject.isAuthenticated()) {
//            // 告知客户端JWT认证失败需跳转到登录页面
//            FMessageVo messageVo = new FMessageVo().back(ResponseCode.NO_AUTH,"");
//            ResponseUtil.responseWrite(JSON.toJSONString(messageVo), servletResponse);
//        } else {
//            //  已经认证但未授权的情况
//            // 告知客户端JWT没有权限访问此资源
//            FMessageVo messageVo =new FMessageVo().back(ResponseCode.NO_AUTH,"");
//            ResponseUtil.responseWrite(JSON.toJSONString(messageVo), servletResponse);
//        }
        // onAccessDenied：表示访问拒绝时是否自己处理，如果返回true表示自己不处理且继续拦截器链执行，返回false表示自己已经处理了（比如重定向到另一个页面）。
        // 过滤链终止
        return false;
    }


    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }


    public void setIAccountService(IAccountService IAccountService) {
        this.IAccountService = IAccountService;
    }


    /**
     * 重定向操作(表单提交才有效)
     *
     * @param request
     * @param response
     */
    public void redirect(HttpServletRequest request, HttpServletResponse response) {
        try {
            response.sendRedirect(request.getContextPath() + "/login.html");
            return;
        } catch (Exception e) {
            return;
        }
    }

    private AuthenticationToken createJwtToken(HttpServletRequest request, String jwt) {
        // 获取所有请求头信息
        Map<String, String> maps = RequestResponseUtil.getRequestHeaders(request);
        //  远程地址待优化
        String ipHost = IpUtil.getIpAddr(request);
        log.debug("ip:" + ipHost);
        return new JwtToken(ipHost, jwt);
    }


//    private Account refreshToken(HttpServletResponse response, String jwt) {
//        JwtAccountDTO accountVo = JsonWebTokenUtil.parseJwt(jwt, JsonWebTokenUtil.SECRET_KEY);
//        String newJwt = JsonWebTokenUtil.issueJWT(accountVo.getTokenId(), RedisDataOptUtil.AUTH_EXPIR_TIME, accountVo.getAccount(), SignatureAlgorithm.HS256);
//        Cookie cookie = new Cookie("jwt", newJwt);
//        response.addCookie(cookie);
//        // 更新
//        redisTemplate.expire(RedisDataOptUtil.APP_AUTH_URL + accountVo.getTokenId(), RedisDataOptUtil.AUTH_EXPIR_TIME, TimeUnit.SECONDS);
//        return accountVo.getAccount();
//    }

    // 验证当前用户是否属于mappedValue任意一个角色
    private boolean checkRoles(Subject subject, Object mappedValue) {
        String[] rolesArray = (String[]) mappedValue;
        return rolesArray == null || rolesArray.length == 0 || Stream.of(rolesArray).anyMatch(role -> subject.hasRole(role.trim()));
    }
}
